package cn.ryh.netty.nio;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**
 * SelectorDemo
 *
 * @author Raoyh
 * @Description
 * @create 2022-09-09 13:36
 */
public class SelectorDemo {
    /**
     * 选择器：
     *  选择器（ Selector） 是 SelectableChannle 对象的多路复用器，
     * Selector 可以同时监控多个 SelectableChannel 的 IO 状况，也就是说，
     * 利用 Selector可使一个单独的线程管理多个 Channel。 Selector 是非阻塞 IO 的核心。
     * <p>
     * 创建Selector：通过调用Selector.open()方法创建一个selector.
     * //创建选择器
     * Selector selector = Selector.open();
     * 向选择器注册通道：SelectableChannel.register(Selector sel,int ops)
     * //创建一个Socket套接字
     * Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9999);
     * //获取SocketChannel
     * SocketChannel socketChannel = socket.getChannel();
     * //创建选择器
     * Selector selector = Selector.open();
     * //将SocketChannel切换到非阻塞模式
     * socketChannel.configureBlocking(false);
     * //向Selector注册Channel
     * SelectionKey key = socketChannel.register(selector,SelectionKey.OP_READ);
     * <p>
     * 当调用 register(Selector sel, int ops) 将通道注册选择器时，
     * 选择器对通道的监听事件，需要通过第二个参数 ops 指定。
     * <p>
     *  可以监听的事件类型（ 可使用 SelectionKey 的四个常量表示）：
     *  读 : SelectionKey.OP_READ （ 1）
     *  写 : SelectionKey.OP_WRITE （ 4）
     *  连接 : SelectionKey.OP_CONNECT （ 8）
     *  接收 : SelectionKey.OP_ACCEPT （ 16）
     *  若注册时不止监听一个事件，则可以使用“位或”操作符连接。例：
     * //注册“监听事件”
     * int interestSet = SelectionKey.OP_READ|SelectionKey.OP_WRITE;
     * <p>
     * SelectionKey
     * 表示 SelectableChannel 和 Selector 之间的注册关系。每次向选择器注册通道时就会选择一个事件(选择键)。
     * 选择键包含两个表示为整数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作。
     *
     * selector.keys() 和  selector.selectedKeys()的区别
     *      keys: 代表所有注册到selector上通道的SelectionKey
     *      selectedKeys: 代表所有注册到selector上有事件发生通道的SelectionKey
     */
    public static void main(String[] args) {
        try {
            // 创建Selector：通过调用Selector.open() 方法创建一个selector.
            Selector selector = Selector.open();
            // 向选择器注册通道：SelectableChannel.register(Selector sel, int ops)
            //创建一个Socket套接字
            SocketChannel socketChannel;
            try (Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999)) {
                //获取SocketChannel
                socketChannel = socket.getChannel();
            }
            //将SocketChannel切换到非阻塞模式
            socketChannel.configureBlocking(false);
            //向Selector注册Channel
            SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
            selector.keys();
            selector.selectedKeys();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
